package com.xielx.httpclikent;

import com.lxxie.commons.StringUtils;
import com.xielx.httpclikent.bean.MyHttpPost;
import com.xielx.httpclikent.bean.MyHttpRequest;
import com.xielx.httpclikent.bean.MyHttpResponse;
import com.xielx.httpclikent.bean.ProxyRequest;
import com.xielx.httpclikent.exception.HttpclientException;
import ohos.app.Context;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.net.NetHandle;
import ohos.net.NetManager;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;

public class MyHttpClient {
    private final static ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 30, 5,
            TimeUnit.MINUTES, new ArrayBlockingQueue<>(1024));
    private final static String CONTENT_ENCODING = "Content-Encoding";
    private final static String GZIP = "gzip";
    private static String proxyUrl;
    private static boolean needProxy;
    private NetHandle netHandle;
    private Context context;

    private MyHttpClient(NetHandle netHandle, Context context) {
        this.netHandle = netHandle;
        this.context = context;
    }

    public static MyHttpClient getInstance(Context context) {
        NetManager manager = NetManager.getInstance(context);
        if (!manager.hasDefaultNet()) {
            throw new HttpclientException("没有找到相应的默认网络");
        }
        NetHandle handler = manager.getDefaultNet();
        if (null == handler) {
            throw new HttpclientException("无法获取到NetHander,请检查config.json中的reqPermissions与cleartextTraffic");
        }
        return new MyHttpClient(handler, context);
    }

    public static void initProxy(String proxy) {
        proxyUrl = proxy;
        needProxy = true;
    }

    public MyHttpResponse doRequest(MyHttpRequest request) {
        HttpURLConnection connection = null;
        try {
            //查看是否使用了代理，如果是的话，转成代理的请求
            if (needProxy) {
                request = new ProxyRequest(proxyUrl, request);
            }
            connection = (HttpURLConnection) netHandle.openConnection(request.toURL());
            for (Map.Entry<String, String> entry : request.getHeader().entrySet()) {
                connection.setRequestProperty(entry.getKey(), entry.getValue());
            }
            connection.setRequestProperty("Accept-Encoding", "gzip, deflate, br");
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
            // 设置请求方式
            connection.setRequestMethod(request.getMethod());
            //请求缓存设为false
            connection.setUseCaches(false);
            // 设置该HttpURLConnection实例是否自动执行重定向
            connection.setInstanceFollowRedirects(true);
            connection.setConnectTimeout(request.getConnectTimeout());
            connection.setReadTimeout(request.getReadTimeout());
            //设置post的相关配置
            if (request.isPost()) {
                // 设置连接输出流为true,默认false (post 请求是以流的方式隐式的传递参数)
                connection.setDoOutput(true);
                // 设置连接输入流为true
                connection.setDoInput(true);
                // 创建输入输出流,用于往连接里面输出携带的参数,(输出内容为?后面的内容)
                DataOutputStream dataout = new DataOutputStream(connection.getOutputStream());
                // 将参数输出到连接
                dataout.write(((MyHttpPost) request).getData());
                // 输出完成后刷新并关闭流
                dataout.flush();
                dataout.close(); // 重要且易忽略步骤 (关闭流,切记!)
            }
            // 建立连接 (请求未开始,直到connection.getInputStream()方法调用时才发起,以上各个参数设置需在此方法之前进行)
            connection.connect();
            InputStream inputStream = connection.getInputStream();
            Map<String, String> firstHeader = new HashMap<>((int) (connection.getHeaderFields().size()));
            boolean isGzip = false;
            for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
                if (CONTENT_ENCODING.equalsIgnoreCase(entry.getKey()) && GZIP.equalsIgnoreCase(entry.getValue().get(0))) {
                    isGzip = true;
                }
                firstHeader.put(entry.getKey(), entry.getValue().get(0));
            }
            // 获取输入流
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            if (isGzip) {
                inputStream = new GZIPInputStream(inputStream);
            }
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = inputStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            byte[] result = outSteam.toByteArray();
            return new MyHttpResponse(connection.getResponseCode(), result, firstHeader);
        } catch (Exception e) {
            e.printStackTrace();
            return new MyHttpResponse(-999, e.getMessage().getBytes());
        } finally {
            if (null != connection) {
                connection.disconnect();
            }
        }
    }

    public void asyncDoRequest(MyHttpRequest request, CallBack callBack) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                MyHttpResponse resp = doRequest(request);
                callBack.callBack(resp);
            }
        };
        if (null == context) {
            pool.execute(runnable);
        } else {
            this.context.getGlobalTaskDispatcher(TaskPriority.DEFAULT).asyncDispatch(runnable);
        }
    }

    public interface CallBack {
        void callBack(MyHttpResponse response);
    }
}
